Learning RSpec, Part II
In the first entry, one of the issues I addressed was stubbing a response to an HTTP-Basic Authentication scheme. To get my spec to pass, I stubbed the entire authenticate method which I had written. While this approach was successful, it left me with a hole in my code coverage:

Now that I knew my controllers' actions were being tested, I needed a good way to test the authenticate method itself, to ensure that failed requests were not being let through. A quick glance in the Rails source gave me some clues to implementation.
Since the credentials are sent (encoded) in the HTTP header, the first thing I needed to do was inject those credentials into the header before the request was processed. Rails core (using Test::Unit) uses the following convenience method in /actionpack/test/controller/http_authentication_test.rb
def set_headers(value = @credentials, name = 'HTTP_AUTHORIZATION')
@controller.request.env[name] = value
end
The encoded credentials are passed in and assigned to the request environment. Accomplishing this in RSpec wasn't much different. First, we construct a set of encoded credentials, then we assign them to the environment variable 'HTTP_AUTHORIZATION'. Note that in the RSpec code below, we don't call @controller.request.env, but simply request.env
before(:each) do
@credentials = ActionController::HttpAuthentication::Basic.encode_credentials("david", "clearly_false")
request.env['HTTP_AUTHORIZATION'] = @credentials
end
This allowed me to create a series of tests to check that a user providing invalid credentials was not being allowed into the protected areas of the site.
it "should fail with invalid credentials" do
get :index
response.should_not be_success
response.headers["Status"].should =~ /401/
end
Two fairly simple expectations, when attempting to access a resource using invalid credentials, the response should not be a success, and the status code should match 401 (Unauthorized).
RSpec is definitely growing on me, and I've noticed some BDD disciplines starting to creep into my approach to testing with Test::Unit in my day job.
